package com.unbiz.tuple;

import java.util.Map;
import java.util.Objects;

import org.apache.commons.collections4.KeyValue;

/**
 * @author A N M Bazlur Rahman
 * @since 3/15/15.
 */
public class Tuple2<T0, T1> extends Tuple<Tuple2<T0, T1>> implements KeyValue<T0, T1> {
    public final T0 _0;
    public final T1 _1;

    public Tuple2(T0 _0, T1 _1) {
        this._0 = _0;
        this._1 = _1;
    }
    
    public Tuple2(Tuple2<T0, T1> tuple) {
    	this._0 = tuple._0;
        this._1 = tuple._1;
    }

    @Override
    public int size() {
        return 2;
    }

    public static <T0, T1> Tuple2<T0, T1> of(T0 _0, T1 _1) {
        return new Tuple2<>(_0, _1);
    }

    @Override
    public Object apply(int value) {
        switch (value) {
            case 0:
                return _0;
            case 1:
                return _1;
            default:
                throw new IndexOutOfBoundsException();
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Tuple2)) return false;

        Tuple2 tuple2 = (Tuple2) o;

        if (_0 != null ? !_0.equals(tuple2._0) : tuple2._0 != null) return false;
        if (_1 != null ? !_1.equals(tuple2._1) : tuple2._1 != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = _0 != null ? _0.hashCode() : 0;
        result = 31 * result + (_1 != null ? _1.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "(" + _0 + ',' + _1 + ')';
    }
    
    @Override
    public Object[] toArray() {		
		return new Object[] {_0,_1};
	}

	@Override
	public int compareTo(Tuple2<T0, T1> o) {
		// TODO Auto-generated method stub
		Objects.requireNonNull(o);
        if (!getClass().equals(o.getClass())) {
            throw new ClassCastException(o.getClass() + " must equal " + getClass());
        }

        for (int i = 0; i < 2; i++) {
            @SuppressWarnings("unchecked")
            Comparable<Object> l = (Comparable<Object>) apply(i);
            Object r = o.apply(i);
            int c = l.compareTo(r);
            if (c != 0) {
                return c;
            }
        }      
		return 0;
	}
	

	@Override
	public T0 getKey() {
		// TODO Auto-generated method stub
		return _0;
	}

	@Override
	public T1 getValue() {
		// TODO Auto-generated method stub
		return _1;
	}
	
	@Override
	public T0 first(){
		return _0;
    }
}
